package com.zshlong.seckill.controller;

import com.zshlong.seckill.access.AccessLimit;
import com.zshlong.seckill.mq.MQSender;
import com.zshlong.seckill.mq.SeckillMessage;
import com.zshlong.seckill.pojo.SeckillOrder;
import com.zshlong.seckill.pojo.SeckillUser;
import com.zshlong.seckill.prefix.GoodsKey;
import com.zshlong.seckill.prefix.OrderKey;
import com.zshlong.seckill.prefix.SeckillKey;
import com.zshlong.seckill.service.GoodsService;
import com.zshlong.seckill.service.OrderService;
import com.zshlong.seckill.service.SeckillService;
import com.zshlong.seckill.service.SeckillUserService;
import com.zshlong.seckill.util.RedisUtil;
import com.zshlong.seckill.vo.CodeMsg;
import com.zshlong.seckill.vo.GoodsVo;
import com.zshlong.seckill.vo.Result;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;

@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {

	@Autowired
	SeckillUserService userService;
	
	@Autowired
	RedisUtil redisUtil;
	
	@Autowired
	GoodsService goodsService;
	
	@Autowired
	OrderService orderService;
	
	@Autowired
	SeckillService seckillService;

	@Autowired
	MQSender sender;

	/** <goodsId,标记>    true：无库存   false：有库存 */
	private HashMap<Long, Boolean> localOverMap =  new HashMap<Long, Boolean>();

	/** 系统初始化加载 */
	@Override
	public void afterPropertiesSet() throws Exception {
		List<GoodsVo> goodsList = goodsService.listGoodsVo();
		if(goodsList == null) {
			return;
		}
		for(GoodsVo goods : goodsList) {
			redisUtil.set(GoodsKey.getMiaoshaGoodsStock, ""+goods.getId(), goods.getStockCount());
			localOverMap.put(goods.getId(), false);
		}
	}

    @PostMapping("/{path}/doSeckill")
	@ResponseBody
	public Result<Integer> seckill(Model model,SeckillUser user,
								   @RequestParam("goodsId")long goodsId,
								   @PathVariable("path") String path) {
		model.addAttribute("user", user);
		if(user == null) {
			return Result.error(CodeMsg.SESSION_ERROR);
		}

		//验证path
		boolean check = seckillService.checkPath(user, goodsId, path);
		if(!check){
			return Result.error(CodeMsg.REQUEST_ILLEGAL);
		}
		//内存标记，减少redis访问
		boolean over = localOverMap.get(goodsId);
		if(over) {
			return Result.error(CodeMsg.MIAO_SHA_OVER);
		}
		//预减库存
		long stock = redisUtil.decr(GoodsKey.getMiaoshaGoodsStock, ""+goodsId);//10
		if(stock < 0) {
			localOverMap.put(goodsId, true);
			return Result.error(CodeMsg.MIAO_SHA_OVER);
		}
		//判断是否已经秒杀到了
		SeckillOrder order = orderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);
		if(order != null) {
			return Result.error(CodeMsg.REPEATE_MIAOSHA);
		}
		//入队
		SeckillMessage msg = new SeckillMessage();
		msg.setUser(user);
		msg.setGoodsId(goodsId);
		sender.sendSeckillMessage(msg);
		return Result.success(0);//排队中
	}

	/**
	 * orderId：成功
	 * -1：秒杀失败
	 * 0： 排队中
	 * */
	@GetMapping(value="/result")
	@ResponseBody
	public Result<Long> seckillResult(Model model,SeckillUser user, @RequestParam("goodsId")long goodsId) {
		model.addAttribute("user", user);
		if(user == null) {
			return Result.error(CodeMsg.SESSION_ERROR);
		}

		long result = seckillService.getSeckillResult(user.getId(), goodsId);
		return Result.success(result);
	}

	@AccessLimit(seconds = 5,maxCount = 5,needLogin = true)
	@GetMapping(value="/path")
	@ResponseBody
	public Result<String> getSeckillPath(HttpServletRequest request, SeckillUser user,
										 @RequestParam("goodsId")long goodsId,
										 @RequestParam(value="verifyCode", defaultValue="0")int verifyCode
	) {
		if(user == null) {
			return Result.error(CodeMsg.SESSION_ERROR);
		}

		boolean check = seckillService.checkVerifyCode(user, goodsId, verifyCode);
		if(!check) {
			return Result.error(CodeMsg.REQUEST_ILLEGAL);
		}
		String path  = seckillService.createSeckillPath(user, goodsId);
		return Result.success(path);
	}

	@GetMapping(value="/verifyCode")
	@ResponseBody
	public Result<String> getSeckillVerifyCod(HttpServletResponse response, SeckillUser user,
											  @RequestParam("goodsId")long goodsId) {
		if(user == null) {
			return Result.error(CodeMsg.SESSION_ERROR);
		}

		try {
			BufferedImage image  = seckillService.createVerifyCode(user, goodsId);
			OutputStream out = response.getOutputStream();
			ImageIO.write(image, "JPEG", out);
			out.flush();
			out.close();
			return null;
		}catch(Exception e) {
			e.printStackTrace();
			return Result.error(CodeMsg.MIAOSHA_FAIL);
		}
	}


	/** 重置数据测试使用 */
	@GetMapping(value="/reset")
	@ResponseBody
	public Result<Boolean> reset(Model model) {
		List<GoodsVo> goodsList = goodsService.listGoodsVo();
		for(GoodsVo goods : goodsList) {
			goods.setStockCount(10);
			redisUtil.set(GoodsKey.getMiaoshaGoodsStock, ""+goods.getId(), 10);
			localOverMap.put(goods.getId(), false);
		}
		redisUtil.delete(OrderKey.getMiaoshaOrderByUidGid);
		redisUtil.delete(SeckillKey.isGoodsOver);
		seckillService.reset(goodsList);
		return Result.success(true);
	}
}